package uia.alumni.data;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;



/**
 *
 * @author Even Åby Larsen (even.larsen@uia.no)
 */
@Entity @Table(name="is202_alumni_user")
@NamedQueries({
    @NamedQuery(
        name="User.findAll",
        query="SELECT u FROM User u ORDER BY u.email"
    ),
    @NamedQuery(
        name="User.findByName",
        query="SELECT u FROM User u WHERE u.fullName LIKE :fullName"
    ),
    @NamedQuery(
        name="User.findByEmail",
        query="SELECT u FROM User u WHERE u.email LIKE :email"
    )
})
public class User {
    
    @Id() @GeneratedValue()
    @Column(name="user_id")
    private long uid;

    @Column(name = "user_email", unique=true, nullable=false)
    private String email;

    @Column(name="user_password")
    private String password;

    @Column(name="user_locked")
    private boolean locked;

    @OneToMany(mappedBy="user",cascade=CascadeType.ALL)
    private Set<UserRole> userRoles;

    @Transient
    private Set<Role> roles;

    @Column(name = "user_full_name")
    private String fullName;

    @Column(name="user_address")
    private String address;

    @Column(name="user_phone")
    private String phone;

    @Lob // Large text string.
    @Column(name="user_description")
    private String description;

    /** The experience list is meaningless without the User
     * so CascadeType.ALL makes sense here.     */
    @OneToMany(mappedBy="user", cascade=CascadeType.ALL)
    @OrderBy("fromDate DESC")
    private List<CvEntry> cv;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, targetEntity = GroupParticipation.class)
    private List<GroupParticipation> groups;

    @OneToMany(mappedBy="gOwner")
    private List<Group> ownedGroups;

    public final static long serialVersionUID = 7;

    // Constructors.
    public User() {
        this(null, null);
    }

    public User(String email, String password) {
        this.email = email;
        this.password = password;
        this.locked = false;
        userRoles = new HashSet<UserRole>();
        fullName = "";
        address = "";
        phone = "";
        description = "";
        cv = new ArrayList<CvEntry>();
        ownedGroups = new ArrayList<Group>();
    }

    // Methods.

    public Set<Role> getRoles() {
        if (roles == null) {
            roles = new HashSet<Role>();
            for (UserRole ur : userRoles)
                roles.add(Role.valueOf(ur.getRoleName()));
        }
        return roles;
    }

    public boolean hasRole(Role role) {
        return getRoles().contains(role);
    }

    public void addRole(Role role) {
        if (!hasRole(role)) {
            roles.add(role);
            userRoles.add(new UserRole(this, role.name()));
        }
    }

    public void removeRole(Role role) {
        if (hasRole(role)) {
            roles.remove(role);
            UserRole ur = null;
            for (UserRole tmp : userRoles)
                if (tmp.getRoleName().equals(role.name()))
                    ur = tmp;
            userRoles.remove(ur);
        }
    }

    /**
     * Check if a user is a user :)
     * Used for Auth check on login.
     *
     * @param email
     * @param password
     * @return return true or false based on input
     */
    public boolean isUser(String email, String password){
        return getPassword().equals(password) && getEmail().equals(email);
    }

    @Override
    public String toString() {
        return getEmail()+";"+getPassword();
    }

    @Override
    public boolean equals(Object that) {
        return (that instanceof User)
                && (this.getUid() == ((User) that).getUid());
    }

    /**  @return the cv */
    public List<CvEntry> getCv() {
        return cv;
    }

    /** Find a cv entry by id
     *  @return the cv entry, or null if it does not exist
     */
    public CvEntry getCvEntry(long id) {
        for (CvEntry cve : cv)
            if (cve.getId() == id) return cve;
        return null;
    }

    /**
     * Add an entry to the cv.
     * @param the new cv entry.
     */
    public void addCvEntry(CvEntry cve) {
        cv.add(cve);
        cve.setUser(this);
    }


    /**
     * Add a group in which this user is a member.
     * @param gp
     */
    public void addGroup(GroupParticipation gp){
        this.getGroupParticipation().add(gp);
    }
    
    /**
     * Return the groups in which the user is a member or admin.
     * @return
     */
    public ArrayList<Group> getGroups(){
        ArrayList<Group> tmp_g = new ArrayList<Group>();
        for(GroupParticipation gp : this.getGroupParticipation()){
            tmp_g.add(gp.getGroup());
        }
        return tmp_g;
    }

    /**
     * Remove an entry from the cv
     */
    public void removeCvEntry(CvEntry cve) {
        if (cv.remove(cve)) cve.setUser(null);
    }

    // Getters and Setters
    public long getUid() {
        return uid;
    }

    public void setUid(long uid) {
        this.uid = uid;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public boolean isLocked() {
        return locked;
    }

    public void setLocked(boolean locked) {
        this.locked = locked;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<GroupParticipation> getGroupParticipation() {
        return groups;
    }

    public void setGroups(List<GroupParticipation> groups) {
        this.groups = groups;
    }


}
